---
id: configuration
title: 2.1 配置
sidebar_label: 2.1 配置
---

import useBaseUrl from "@docusaurus/useBaseUrl";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

:::important 温馨提示

推荐使用 《[2.2 选项](options.mdx)》代替本章节功能。（[为什么](#217-配置的优缺点)）？

:::

## 2.1.1 什么是配置

简单来说，配置将系统应用可动态调配的选项放在统一地方管理，通过不同的配置让系统做出动态调整。

在 `ASP.NET Core` 应用程序启动时默认加载 `启动项目` 下的 `appsettings.json` 作为应用配置。同时还支持**不同的运行环境**加载对应的配置文件，如：

- `Development`：加载 `appsettings.Development.json`
- `Staging`：加载 `appsettings.Staging.json`
- `{Environment}`：`appsettings.{Environment}.json`

## 2.1.2 配置的使用

假设我们需要在系统运行时获取**系统名称、版本号及版权信息**，这些信息可能随时变化而且需要在多个地方使用。这时就需要将这些信息配置起来。具体步骤如下：

### 配置 `appsettings.json` 信息

```json {2-6}
{
  "AppInfo": {
    "Name": "Fur",
    "Version": "1.0.0",
    "Company": "Baiqian"
  }
}
```

### 读取 `appsettings.json` 信息

在 `Fur` 框架中，提供了两种读取方式：

- 依赖注入 `IConfiguration` 对象读取
- 通过 `App.Configuration[jsonKey]` 读取

<Tabs
  defaultValue="App.Configuration[jsonKey]"
  values={[
    {
      label: "App.Configuration[jsonKey]",
      value: "App.Configuration[jsonKey]",
    },
    { label: "依赖注入方式", value: "依赖注入方式" }
  ]}
>
  <TabItem value="App.Configuration[jsonKey]">


```cs {11-13}
using Microsoft.AspNetCore.Mvc;

namespace Fur.Web.Entry.Controllers
{
    [Route("api/[controller]")]
    public class DefaultController : ControllerBase
    {
        [HttpGet]
        public string Get()
        {
            return $@"名称：{App.Configuration["AppInfo:Name"]}，
                      版本：{App.Configuration["AppInfo:Version"]}，
                      公司：{App.Configuration["AppInfo:Company"]}";
        }
    }
}
```

  </TabItem>
  <TabItem value="依赖注入方式">


```cs {2,10-15}
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace Fur.Web.Entry.Controllers
{
    [Route("api/[controller]")]
    public class DefaultController : ControllerBase
    {
        [HttpGet]
        public string Get([FromServices] IConfiguration configuration)
        {
            return $@"名称：{configuration["AppInfo:Name"]}，
                      版本：{configuration["AppInfo:Version"]}，
                      公司：{configuration["AppInfo:Company"]}";
        }
    }
}
```

  </TabItem>
</Tabs>


:::tip 依赖注入的方式

通过依赖注入注入实例有几种方式：

- 构造函数注入方式

```cs {2}
private readonly IConfiguration _configuration;
public DefaultController(IConfiguration configuration)
{
    _configuration = configuration;
}
```

- 参数注入方式 `[FromServices]`

```cs {1}
public string Get([FromServices] IConfiguration configuration)
{
}
```

- 属性注入方式

```cs {1}
public IConfiguration Configuration { get; set; }
```

想了解更多关于《[ASP.NET Core - 依赖注入](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1)》 知识

:::

### 如何选择读取方式

- 在可依赖注入类中，依赖注入 `IConfiguration` 读取
- 在静态类/非依赖注入类中，选择 `App.Configuration[jsonKey]` 读取

## 2.1.3 分层读取数据

在 `ASP.NET Core` 中，配置采用 `:` 分隔符来读取分层配置数据。如上述例子中的 `AppInfo:Name`。如有更多层级数据则只需要通过 `:` 进入下一层节点即可。

假设我们有以下配置信息：

```json {5-12}
{
  "AppInfo": {
    "Name": "Fur",
    "Version": "1.0.0",
    "Company": {
      "Name": "Baiqian",
      "Address": {
        "City": "中国",
        "Province": "广东省",
        "Detail": "中山市东区紫马公园西门"
      }
    }
  }
}
```

<Tabs
  defaultValue="two"
  values={[
    { label: "读取第二层", value: "two" },
    { label: "读取第三层", value: "three" },
    { label: "读取第四层", value: "four" },
    { label: "读取第N层", value: "n" },
  ]}
>
  <TabItem value="two">


```cs
var companyName = App.Configuration["AppInfo:Name"]; // => Fur
```

  </TabItem>
  <TabItem value="three">


```cs
var companyName = App.Configuration["AppInfo:Company:Name"]; // => Baiqian
```

  </TabItem>
  <TabItem value="four">


```cs
var companyName = App.Configuration["AppInfo:Company:Address:Detail"]; // => 中山市东区紫马公园西门
```

  </TabItem>
  <TabItem value="n">


```cs
var companyName = App.Configuration["AppInfo:Tier2:Tier3:Tier4...Tiern1:Tiern2..."]; // => 中山市东区紫马公园西门
```

  </TabItem>
</Tabs>


## 2.1.4 自定义配置文件

大多情况下，我们的配置只需要在 `appsettings.json` 中配置即可，但一些特殊情况下，我们希望某些组件或功能拥有独立的配置，比如邮件配置：

```json {2-13} title="Fur.Web.Entry/emailsetting.json"
{
  "outlook": {
    "smtp": {
      "server": "smtp.office365.com",
      "port": "587",
      "ssl": "STARTTLS"
    },
    "pop": {
      "server": "outlook.office365.com",
      "port": "995",
      "ssl": "TLS"
    }
  }
}
```

`ASP.NET Core` 提供了非常灵活的方式支持多个配置文件配置及读取，配置如下：

### 在 `Program.cs` 中添加配置文件

```cs {2,16-19} title="Fur.Web.Entry/Program.cs"
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace Fur.Web.Entry
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration(configurationBuilder =>
                {
                    configurationBuilder.AddJsonFile("emailsetting.json", optional: true, reloadOnChange: true);
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}
```

### 读取 `emailsetting.json` 配置

读取自定义配置文件和读取 `appsettings.json` 一致，系统会自动从多个配置文件中读取输入，如：

<Tabs
  defaultValue="jtl"
  values={[
    {label: 'App.Configuration[jsonKey]', value: 'jtl'},
    {label: '依赖注入方式', value: 'ylzr'}
  ]}>
  <TabItem value="jtl">


```cs
var smtpServer = App.Configuration["outlook:smtp:server"]; // => smtp.office365.com
```

  </TabItem>
  <TabItem value="ylzr">


```cs
var smtpServer = _configuration["outlook:smtp:server"]; // => smtp.office365.com
```

  </TabItem>
</Tabs>


## 2.1.5 不同环境读取

在实际应用开发中，我们可能会根据不同的环境加载不同的配置文件，如 `数据库连接字符串`。

这时我们只需要遵循特定命名规范 `{name}.{Environment}.json` 即可。如：

- `appsettings.Development.json`
- `appsettings.Staging.json`
- `appsettings.Production.json`
- `emailsetting.Development.json`
- `emailsetting.Staging.json`
- `emailsetting.Production.json`

这时，`ASP.NET Core` 会在应用启动时自动加载不同环境的配置文件。

## 2.1.6 配置更改通知（`热更新`）

在 `.NET Core` 应用程序中，配置支持更改通知，也就是热更新操作。**一旦监听到 `appsetting.json` 或自定义配置文件发生变动，就会触发 `OnChange` 方法**。代码如下：

```cs {2,4-5}
var appInfoConfiguration = App.Configuration["AppInfo"];
ChangeToken.OnChange(() => appInfoConfiguration.GetReloadToken(), () =>
{
  var name = appInfoConfiguration["Name"];  // 实时的最新值
  var version = appInfoConfiguration["Version"];  // 实时的最新值
});
```

## 2.1.7 配置的优缺点

### 优点

- 能够在系统运行时快速读取
- 无需额外配置

### 缺点

- 存在重复读取
- 通过硬编码字符串读取，容易出错
- 不能设置默认值
- 不能在运行环境中动态配置
- 不能验证配置有效性
- 不支持更改通知

## 2.1.8 配置使用场景

如果只需要**一次性读取**配置信息，则使用配置，否则应该使用 《[2.2 选项](options.mdx)》代替。

## 2.1.9 反馈与建议

:::note 与我们交流

给 Fur 提 [Issue](https://gitee.com/monksoul/Fur/issues/new?issue)。

:::

---

:::note 了解更多

想了解更多 `配置` 知识可查阅 [ASP.NET Core - 配置](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0) 章节。

:::
